/******************************************************************************* * Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. *******************************************************************************/ package org.cloudifysource.shell; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.PrintStream; import java.io.SequenceInputStream; import java.net.Proxy; import java.net.ProxySelector; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import jline.Terminal; import jline.console.ConsoleReader; import org.apache.felix.gogo.commands.Action; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; import org.apache.felix.gogo.runtime.CommandProcessorImpl; import org.apache.felix.service.command.CommandSession; import org.apache.karaf.shell.console.Main; import org.apache.karaf.shell.console.jline.Console; import org.cloudifysource.shell.exceptions.CLIException; import org.cloudifysource.shell.logging.ShellErrorManager; import org.cloudifysource.shell.logging.ShellFormatter; import org.cloudifysource.shell.proxy.SystemDefaultProxySelector; import org.fusesource.jansi.Ansi; /** * @author rafi, barakm, adaml, noak * @since 2.0.0 * * Extends the Karaf framework Main object. This class is used to start the shell/console. */ // declared as command so that it can be used in the context of another shell @Command(name = "cloudify", scope = "cloudify", description = "Executes a cloudify command interpreter") public final class GigaShellMain extends Main implements Action { private static final String EXIT_COMMAND = "exit\n"; private static GigaShellMain instance; private ConsoleWithProps console; private final boolean isInteractive; private static final String[] BLOCKED_LOGGERS = new String[] { "org.cloudifysource.esc.jclouds.JCloudsDeployer" }; @Argument(name = "args", description = "Cloudify sub command arguments", multiValued = true) private String[] args; /** * This is the shell's main method. It starts the shell, sets the logging configurations, and the proxy if * configured. Arguments, if passed, are expected in 1 of these 2 formats: -f <file_name> OR <command 1>;<command * 2>;<command 3>;.... Passing commands set the interactive mode off. * * @param args * The commands to be executed, either in a file or as a list. * @throws Exception * Reporting a failure to start the shell or execute the commands */ public static void main(final String[] args) throws Exception { String[] actualArgs = args; initializeLogConfiguration(); initializeProxyConfiguration(); InputStream is = null; SequenceInputStream sis = null; final InputStream exitInputStream = new ByteArrayInputStream(EXIT_COMMAND.getBytes()); boolean isInteractive = true; try { if (args.length > 0) { isInteractive = false; if (args[0].startsWith("-f=")) { final String filename = args[0].substring("-f=".length()); final File file = new File(filename); if (!file.exists()) { throw new IllegalArgumentException(filename + " does not exist"); } is = new FileInputStream(filename); } else { String commandString = ""; for (String arg : args) { commandString = commandString.concat(arg + " "); } if (!commandString.endsWith(";")) { commandString = commandString.concat(";"); } commandString = commandString.replace(";", System.getProperty("line.separator")); is = new ByteArrayInputStream(commandString.getBytes("UTF-8")); } sis = new SequenceInputStream(is, exitInputStream); System.setIn(sis); actualArgs = new String[0]; } instance = new GigaShellMain(isInteractive); instance.setApplication("cloudify"); Ansi.ansi(); instance.run(actualArgs); } finally { if (is != null) { is.close(); } if (sis != null) { sis.close(); } exitInputStream.close(); } } private GigaShellMain(final boolean isInteractive) { this.isInteractive = isInteractive; } private static void initializeLogConfiguration() { // Replace the console Handler's formatter. final Handler[] handlers = Logger.getLogger("").getHandlers(); for (final Handler handler : handlers) { if (handler.getClass().getName().equals(ConsoleHandler.class.getName())) { handler.setFormatter(new ShellFormatter()); handler.setErrorManager(new ShellErrorManager()); handler.setLevel(Level.INFO); break; } } // block info printouts from specific internal components. for (final String loggerName : BLOCKED_LOGGERS) { Logger.getLogger(loggerName).setLevel(Level.WARNING); } } private static void initializeProxyConfiguration() { // SystemDefaultProxySelector has not been tested on different platforms if (!ShellUtils.isWindows()) { return; } if (!Boolean.getBoolean(Constants.ENABLE_PROXY_CONFIGURATION_PROPERTY)) { return; } if (isProxySettingsDefined()) { return; } try { SystemDefaultProxySelector.setup(); } catch (final Exception e) { Logger.getLogger(GigaShellMain.class.getName()).log(Level.WARNING, "Failed using system proxy configuration, falling back to no proxy.", new CLIException(e)); } } // TODO this is not very robust and needs much more work to get done right private static boolean isProxySettingsDefined() { try { final URI someURI = new URI("http://www.example.com"); final ProxySelector defaultSelector = ProxySelector.getDefault(); final List<Proxy> proxies = defaultSelector.select(someURI); return !proxies.isEmpty() && !proxies.get(0).equals(Proxy.NO_PROXY); } catch (final URISyntaxException e) { // Will not happen return false; } } /** * Gets the single instance of this class. * * @return the single instance of this class */ public static GigaShellMain getInstance() { return instance; } /** * {@inheritDoc} */ @Override public Object execute(final CommandSession session) throws Exception { run(session, args); return null; } /** * {@inheritDoc} */ @Override protected Console createConsole(final CommandProcessorImpl commandProcessor, final InputStream input, final PrintStream output, final PrintStream err, final Terminal terminal) throws Exception { // Disable PC speaker beep System.setProperty(ConsoleReader.JLINE_NOBELL, Boolean.toString(true)); final CloseCallback callback = new CloseCallback(); console = new ConsoleWithProps(commandProcessor, input, output, err, terminal, callback, isInteractive); return console; } /** * Sets the current application name. * * @param applicationName * The application name */ public void setCurrentApplicationName(final String applicationName) { console.setCurrentApplicationName(applicationName); } /** * {@inheritDoc} */ @Override public String getDiscoveryResource() { return "META-INF/shell/commands"; } /** * {@inheritDoc} */ @Override public boolean isMultiScopeMode() { return false; } }